#!/usr/bin/env python

import gtk
import pango
import gettext
import constants as iconstants
from mxit import handles
from signals import chatWindowSignals
from blend import const
from blend import conversation
from blend import parser
from blend import constants
import emoticons
import multimxTab, mxmTab
import htmltextview
import gtk.keysyms
import gobject
import types
import time
from blend import debug

try:
   import gtkspell
   spel = True;   # Yes, it's supposed to be with one 'l'
except ImportError:
   spel = False;

gettext.install('blendIT','locale');

class chatWindow(gtk.Window):

   def __init__(self,blend):
      gtk.Window.__init__(self,gtk.WINDOW_TOPLEVEL);
      gtk.rc_parse('blend.rc');

      self.set_title(_("Conversation"));
      self.set_geometry_hints(min_width=150, min_height=150);
      self.set_default_size(560,600); # TO DO - Persistant GUI Dimensions
      self.set_icon_from_file("images/blendit.png");
      self.accel_group = gtk.AccelGroup();

      self.sigs = chatWindowSignals.signals(blend);
      self.convs = conversation.Conversations();
      self.emoticons = emoticons.emoticons(blend.temp,True); # <-- check conf for secodn attribute
      self.parser = parser.Parser(blend); 
      self.blend = blend;

      self.notebook = gtk.Notebook();
      self.notebook.show();
      self.notebook.connect('switch-page',self.sigs.on_notebook_change);
      self.notebook.connect('page-removed',self.sigs.on_notebook_remove);
      menu = self.drawMenu(self.accel_group);
      
      vbox = gtk.VBox();
      vbox.pack_start(menu,False,False);
      vbox.pack_start(self.notebook,True,True);
      vbox.show();
      self.set_border_width(4);

      self.add(vbox);
      self.add_accel_group(self.accel_group);
      self.connect('delete-event',self.sigs.on_delete);

   # This will create a new chat in the chat window
   def createNewChat(self,buddy,focus=False,method=None):
      # Firstly, does the chat exist already?
      n = self.convs.getPageNumberFromJID(buddy.jid);
      if n is not None:
         if focus:
            self.show();
            self.grab_focus();
            self.notebook.set_current_page(n);
         return;

      if method == None:
         method = self.drawPrivatePage;

      if focus is True:
         self.show();
         self.grab_focus();
      
      n = method(buddy);

      if n == -1:
         return -1;

      if focus is True:
         # Whoa. Hold on there buddy. If this is a splash, we can't allow
         # it to grab confus if the convs is > 1
         if len(self.convs) > 1:
            if buddy.type != handles.BuddyType.SPLASH:
               if not buddy.isService():
                  self.disableBuddyMenuOptions();
               self.notebook.set_current_page(n);
         else:
            if not buddy.isService():
               self.enableBuddyMenuOptions();
            self.notebook.set_current_page(n);

      if buddy.isService():
         self.blend.gui.chatWindow.disableBuddyMenuOptions();
      else:
         self.blend.gui.chatWindow.enableBuddyMenuOptions();      

      if self.convs.len == 1:
         title = "%s - %s" % ((buddy.name),_("Conversation"));
         self.set_title(title);
         self.set_icon_from_file(constants.C.Presence[buddy.presence].timage);
          

      if buddy.isService():
         self.blend.mxitmessage.sendMessage(buddy.jid,'',False);

      return n;

   def destroyAllChats(self):
      for i in range(self.convs.len-1,-1,-1):
         self.destroyChat(i);

   # There is an easier way to do this whole thing.. but I did it silly-ly
   # and now it's just too much work to change it :(
   # Hmm.. No idea why I have removePage there .. since it must never be
   # false.. unless you want total and utter failure of life as we know it!
   def destroyChat(self,n=-1,removePage=True,jid=False):
      if jid:
         n = self.convs.getPageNumberFromJID(jid);

      if self.blend.chatLogger:
         conv = self.convs.getByPageNumber(n);
         self.blend.chatLogger.endLog(conv);

      child = self.notebook.get_nth_page(n);
      child.hide();
      self.convs.removeConversationByPageNumber(n);
      self.notebook.remove_page(n);

      return True;

   def errorMessage(self,message,convs=[],spawn=False,jids=[]):
      if self.get_property('visible') == False:
         self.show();

      if len(convs) == 0:
         # jids must get converted
         for i in range(0,len(jids)):
            conv = self.convs.getByJID(jids[i]);
            if conv is not None:
               convs.append(self.convs.getByJID(jids[i]));
            else:
               if spawn is True:
                  buddy = self.blend.mxit.conn.roster.get_buddy(jids[i]);
                  self.createNewChat(buddy);
                  convs.append(self.convs.getByJID(jids[i]));

      e = _("Error: ");
      msg = '<div>'
      msg += '<span style="color: #FF0000; font-weight: bold">%s%s' % (e,message);
      msg += '</span></div>'
      
      for i in range(0,len(convs)):
         try:
            convs[i].view.display_html(msg);
            # Add to logger
            if self.blend.chatLogger:
               if convs[i].logRes and convs[i].logging_messages == True:
                  self.blend.chatLogger.log(convs[i],msg);
               if not convs[i].logRes and convs[i].logging_messages == True:
                  self.blend.chatLogger.start(convs[i]);
         except AttributeError:
            pass;

   def systemMessage(self,message,convs=[],spawn=False,jids=[]):
      if self.get_property('visible') == False:
         self.show();

      if len(convs) == 0:
         # jids must get converted
         for i in range(0,len(jids)):
            conv = self.convs.getByJID(jids[i]);
            if conv is not None:
               convs.append(self.convs.getByJID(jids[i]));
            else:
               if spawn is True:
                  buddy = self.blend.mxit.conn.roster.get_buddy(jids[i]);
                  self.createNewChat(buddy);
                  convs.append(self.convs.getByJID(jids[i]));

      msg = '<div>'
      msg += '<span style="color: %s; font-style: italic">%s' % (iconstants.COLOUR_System,message);
      msg += '</span></div>'
      
      for i in range(0,len(convs)):
         try:
            convs[i].view.display_html(msg);
            mark = convs[i].view.get_buffer().get_mark('end');
            convs[i].view.scroll_to_mark(mark,0.05,True,0.0,1.0);

            # Add to logger
            if self.blend.chatLogger:
               if convs[i].logRes and convs[i].logging_messages == True:
                  self.blend.chatLogger.log(convs[i],msg);
               if not convs[i].logRes and convs[i].logging_messages == True:
                  self.blend.chatLogger.start(convs[i]);
         except AttributeError:
            pass;

   def parseMessage(self,message,conv,log=True,col=None):
      if self.get_property('visible') == False:
         self.show();

      msg = message.message;
      msg = self.parser.sanitiseParser(msg);

      if message.type == handles.MessageType.COMMAND:
         msg = str(self.parser.commandParse.parse(msg));
      
      if handles.MessageFlags.MARKUP in message.flags:
         m = str(self.parser.parse(msg,parser.MARKUP));
      else:
         m = str(self.parser.parse(msg));
     
      if handles.MessageFlags.CUSTOM_EMOTICONS in message.flags:
         m = self.emoticons.findCustomEmoticons(m);

      if type(message.time) == type(float(1)):
         t = message.time;
      else:
         t = float(time.mktime(message.time.timetuple())); 
         
      ti = time.strftime(self.blend.config.timeformat,time.localtime(t));

      if type(message.buddy) == types.StringType:
         colour = iconstants.COLOUR_Blue;
         name = message.buddy;
         message.buddy = handles.Buddy('',name,'');
      else:
         colour = iconstants.COLOUR_Red;
         name = message.buddy.name;
      
      if col != None:
         colour = col;
      
      txt = '<div><span style="color: %s; font-size: small">(%s) </span>';
      txt += '<span style="color: %s; font-weight: bold">%s:  </span>';
      txt += '<span>%s</span><br/>\n</div>\n';
      mesg = txt % (colour,ti,colour,str(name),m);
      if self.blend.config.debug == True:
         print "We shall be sending", mesg;
      conv.view.display_html(mesg);
      mark = conv.view.get_buffer().get_mark('end');
      conv.view.scroll_to_mark(mark,0.05,True,0.0,1.0);

      # Add to logger
      if log == True:
         if self.blend.chatLogger:
            if conv.logRes and conv.logging_messages == True:
               self.blend.chatLogger.log(conv,mesg);
               self.blend.chatLogger.glog(conv,message);
            if not conv.logRes and conv.logging_messages == True:
               self.blend.chatLogger.start(conv);
               self.blend.chatLogger.log(conv,mesg);
               self.blend.chatLogger.glog(conv,message)

      # Finally, check to see if we did have any custom emoticons
      # to download.
      if handles.MessageFlags.CUSTOM_EMOTICONS in message.flags:
         if m.find("customEmote") != -1:
            self.emoticons.getCustomEmoticons(conv,m);


   def updateBuddyMood(self,buddy):
      jid = buddy.jid;
      conv = self.convs.getByJID(jid);

      if conv is None:
         return;

      conv = self.convs.updateConversation(jid,buddy);
      mood = constants.C.moods[buddy.mood];
      text = _("%(name)s is now %(mood)s") % {'name': str(conv.buddy.name), 'mood': str(mood.text)};
      if mood.const is handles.Mood.NONE:
         return;
      elif mood.const in (handles.Mood.SAD,handles.Mood.SICK):
         text += '</span> - <span style="font-size: small"> ';
         text += '<a href="blendit://sendmessage:%s!">%s</a></span> ' % (_("hug"),_("send a hug"));
         text += '<span style="font-style: italic">';
      # Send a systemMessage.
      self.systemMessage(text,[conv],False);


   def updateConversationFilePending(self,jid,file):
      conv = self.convs.getByJID(jid);
      if conv is None:
         # There is no conversation. We will have to make one
         buddy = self.blend.conn.roster.get_buddy(jid);
         pageN = self.createNewChat(buddy);
         conv = self.convs.getByPageNumber(pageN);
         if conv is None:
            if self.blend.config.debug == True:
               print "unexplained error!";
            return
         

      text = "%s wants to send %s" % (str(conv.buddy.name),str(file.name));
      text += '</span><span style="font-size: small"> ';
      text += '<a href="blendit://accept:%s">%s</a>' % (str(file.id),
                                                        _("Download"));
      self.systemMessage(text,[conv],True);
      
      if file.description is not u'':
         self.systemMessage(_("Description: %s") % str(file.description),
                            [conv],False);


   # Updates the buddy's status in the chat Window
   def updateBuddyPresence(self,buddy):
      jid = buddy.jid;
      conv = self.convs.getByJID(jid);

      if conv is None:
         return;

      conv = self.convs.updateConversation(jid,buddy);

      # Redraw the label
      presence = constants.C.presences[conv.buddy.presence];
      self.drawLabel(conv.buddy.name,presence,
                     self.convs.getPageNumberFromJID(jid),
                     jid);
         
      # Also put it in the text view
      text = _("%(name)s is now %(status)s") % {'name': str(conv.buddy.name), 'status': presence.text};
      self.systemMessage(text,[conv],False);

   # Updates the buddy's name in the chat window
   def updateBuddyName(self,buddy):
      jid = buddy.jid;

      conv = self.convs.updateConversation(jid,buddy);
      if not conv:
         return; # Not in a conversation with this buddy

      oldName = str(self.convs.getByJID(jid).buddy.name);

      # Redraw the label
      presence = constants.C.presences[conv.buddy.presence];
      self.drawLabel(conv.buddy.name,presence,
                     self.convs.getPageNumberFromJID(jid),
                     jid);
         
      # Also put it in the text view
      text = _("%(oldName)s is now known as %(newName)s") % {'oldName': oldName, 'newName': str(conv.buddy.name)};
      self.systemMessage(text,[conv],False);


   # Update the label if in a conversation with the buddy
   def updateBuddyMessage(self,buddy=None,col=False):
      if buddy is None:
         n = self.notebook.get_current_page();
         conv = self.convs.getByPageNumber(n);
         if conv is None:
            return;
         buddy = conv.buddy

      jid = buddy.jid

      conv = self.convs.getByJID(jid);
      if not conv:
         return; # Not in a conversation with this buddy
      
      
      # This is a service or a multimx so we aren't going to update the label
      if conv.buddy.isService() or conv.private == False:
         return;


      if self.notebook.get_current_page() != self.convs.getPageNumberFromJID(jid):
         if col == True:
            name = "<span color='red'>" + conv.buddy.name + "</span>";
         else:
            name = conv.buddy.name;
      else:
         name = conv.buddy.name

      self.drawLabel(name,constants.C.presences[buddy.presence],
                     self.convs.getPageNumberFromJID(jid),
                     jid);


   def textEntryFocus(self):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      conv.convEntry.grab_focus();


   def drawLabel(self,buddy,presence,n,jid):
      statusImg = gtk.Image();
      statusPixBuf = gtk.gdk.pixbuf_new_from_file_at_size(presence.image,16,16);
      statusImg.set_from_pixbuf(statusPixBuf);

      closeImg = gtk.Image();
      closeImg.set_from_stock(gtk.STOCK_CLOSE,gtk.ICON_SIZE_MENU);
      closeImg.show();
      eventBox = gtk.EventBox();
      eventBox.set_visible_window(False);
      eventBox.add_events(gtk.gdk.BUTTON_PRESS_MASK);
      eventBox.connect('button_press_event',self.sigs.on_tab_close,jid);        
      eventBox.add(closeImg);

      label = gtk.Label(buddy);
      label.set_use_markup(True);      
      
      hbox = gtk.HBox();
      hbox.pack_start(statusImg,False,False);
      hbox.pack_start(label,True,True,4);
      hbox.pack_start(eventBox,False,False);
      hbox.set_spacing(2);
      hbox.show_all();
           
      widget = self.notebook.get_nth_page(n);
      self.notebook.set_tab_label(widget,hbox);

   def enableBuddyMenuOptions(self):
      self.findMenuItem.set_sensitive(True);
      self.viewLogMenuItem.set_sensitive(True);
      self.sendFileMenuItem.set_sensitive(True);
      self.saveChatGalleryMenuItem.set_sensitive(True);
      self.loggingMenuItem.set_sensitive(True);
      self.encryptMenuItem.set_sensitive(True);

   def disableBuddyMenuOptions(self):
      self.findMenuItem.set_sensitive(False);
      self.viewLogMenuItem.set_sensitive(False);
      self.sendFileMenuItem.set_sensitive(False);
      self.saveChatGalleryMenuItem.set_sensitive(False);
      self.loggingMenuItem.set_sensitive(False);
      self.encryptMenuItem.set_sensitive(False);

   def controls(self,conv):
      buttons = gtk.HBox();
      buttons.show();
      
      emoteImg = gtk.Image();
      emoteImg.set_from_file(iconstants.EMOTE_Smile);
      emoteImg.show();
      emoticonsBtn = gtk.Button(_("_Emoticons"));
      emoticonsBtn.set_image(emoteImg);
      emoticonsBtn.connect('clicked',self.sigs.on_emote_btn);
      emoticonsBtn.show();
      emoticonsBtn.set_tooltip_text(_("Emoticons"));
      buttons.pack_start(emoticonsBtn,False,False);

      boldImg = gtk.Image();
      boldImg.set_from_stock(gtk.STOCK_BOLD,gtk.ICON_SIZE_BUTTON);
      boldImg.show();
      boldBtn = gtk.ToggleButton();
      boldBtn.set_image(boldImg);
      boldBtn.connect('clicked',self.sigs.on_bold_btn);
      boldBtn.show();
      boldBtn.set_tooltip_text(_("Bold"));
      buttons.pack_start(boldBtn,False,False);

      italImg = gtk.Image();
      italImg.set_from_stock(gtk.STOCK_ITALIC,gtk.ICON_SIZE_BUTTON);
      italImg.show();
      italBtn = gtk.ToggleButton();
      italBtn.set_image(italImg);
      italBtn.connect('clicked',self.sigs.on_italic_btn);
      italBtn.show();
      italBtn.set_tooltip_text(_("Italics"));
      buttons.pack_start(italBtn,False,False);

      underImg = gtk.Image();
      underImg.set_from_stock(gtk.STOCK_UNDERLINE,gtk.ICON_SIZE_BUTTON);
      underImg.show();
      underBtn = gtk.ToggleButton();
      underBtn.set_image(underImg);
      underBtn.connect('clicked',self.sigs.on_underlined_btn);
      underBtn.show();
      underBtn.set_tooltip_text(_("Underline"));
      buttons.pack_start(underBtn,False,False);

      hiliteImg = gtk.Image();
      hiliteImg.set_from_stock(gtk.STOCK_SELECT_FONT,gtk.ICON_SIZE_BUTTON);
      hiliteImg.show();
      hiliteBtn = gtk.ToggleButton();
      hiliteBtn.set_image(hiliteImg);
      hiliteBtn.connect('clicked',self.sigs.on_highlight_btn);
      hiliteBtn.show();
      hiliteBtn.set_tooltip_text(_("Highlight"));
      buttons.pack_start(hiliteBtn,False,False);

      bigTextImg = gtk.Image();
      bigTextImg.set_from_stock(gtk.STOCK_GO_UP,gtk.ICON_SIZE_BUTTON);
      bigTextImg.show();
      bigTextBtn = gtk.ToggleButton();
      bigTextBtn.set_image(bigTextImg);
      bigTextBtn.connect('clicked',self.sigs.on_bigtext_btn);
      bigTextBtn.show();
      bigTextBtn.set_tooltip_text(_("Bigger Text"));
      buttons.pack_start(bigTextBtn,False,False);

      smallTextImg = gtk.Image();
      smallTextImg.set_from_stock(gtk.STOCK_GO_DOWN,gtk.ICON_SIZE_BUTTON);
      smallTextImg.show();
      smallTextBtn = gtk.ToggleButton();
      smallTextBtn.set_image(smallTextImg);
      smallTextBtn.connect('clicked',self.sigs.on_smalltext_btn);
      smallTextBtn.show();
      smallTextBtn.set_tooltip_text(_("Smaller Text"));
      buttons.pack_start(smallTextBtn,False,False);

      colourImg = gtk.Image();
      colourImg.set_from_stock(gtk.STOCK_SELECT_COLOR,gtk.ICON_SIZE_BUTTON);
      colourImg.show();
      colourBtn = gtk.ToggleButton();
      colourBtn.set_image(colourImg);
      colourBtn.connect('clicked',self.sigs.on_colour_btn);
      colourBtn.show();
      colourBtn.set_tooltip_text(_("Text Colour"));
      buttons.pack_start(colourBtn,False,False);

      conv.convEntry.set_accepts_tab(True);
      conv.convEntry.set_wrap_mode(gtk.WRAP_WORD);
      conv.convEntry.set_editable(True);
      conv.convEntry.set_flags(gtk.CAN_FOCUS);
      conv.convEntry.set_flags(gtk.HAS_GRAB);
      self.addTagsToBuffer(conv);
      conv.convEntry.show();      
      
      # Add the ability to check speling!  -- yes, that was intentional ;)
      if spel == True:
         conv.spell = gtkspell.Spell(conv.convEntry);
         conv.spell.set_language(self.blend.currentAccount.lang);

      conv.convEntry.get_buffer().connect('changed',self.sigs.on_text_changed);
      conv.convEntry.connect('mykeypress',self.sigs.on_key_press_event,conv.jid,
                             buttons);
      conv.convEntry.set_pixels_above_lines(4);
      conv.convEntry.set_left_margin(6);
      conv.convEntry.set_right_margin(6);

      scrollWindow = gtk.ScrolledWindow();
      scrollWindow.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC);
      scrollWindow.add(conv.convEntry);
      scrollWindow.show();
      
      vbox = gtk.VBox();
      vbox.pack_start(buttons,False,False);
      vbox.pack_start(scrollWindow,True,True,4);
      vbox.show();
      
      return vbox;

   def mxmReader(self,buddy):
      conv = conversation.Conversation(buddy);

      mTab = mxmTab.mxmTab(self.blend,conv);
      if mTab.failed == True:
         return -1;
      else:
         n = self.notebook.get_n_pages();
      
         self.notebook.append_page(mTab.scrollWindow,None);
         pres = constants.Presence(None,"",iconstants.IMG_Mxm);      
         self.drawLabel(buddy.name,pres,n,buddy.jid);
         self.convs.addConversation(conv);
         
         mTab.parseMessages();
      
         return n;



   def drawDebugPage(self,buddy):
      deb = debug.debug(self,buddy.jid);

      conv = conversation.Conversation(buddy);

      def des(*args):
         self.blend.logger.removeHandler(deb);

      conv._destroy = des;
      
      # Create a textView
      conv.view = gtk.TextView();
      conv.view.set_pixels_above_lines(4);
      conv.view.set_left_margin(6);
      conv.view.set_right_margin(6);
      conv.view.set_wrap_mode(gtk.WRAP_WORD);
      buf = conv.view.get_buffer();
      buf.create_mark("end",buf.get_end_iter(),False);
      conv.view.show();
      conv.view.modify_font(pango.FontDescription('monospace normal 9'));
      conv.view.set_cursor_visible(False);

      scrollWindow = gtk.ScrolledWindow();
      scrollWindow.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC);
      scrollWindow.add(conv.view);
      scrollWindow.show();
      
      # Add handler
      self.blend.logger.addHandler(deb);
      n = self.notebook.get_n_pages();
      
      self.notebook.append_page(scrollWindow,None);
      pres = constants.Presence(None,"",iconstants.IMG_Debug);      
      self.drawLabel("Debug",pres,n,buddy.jid);
      self.convs.addConversation(conv);
      return n;
      


   def drawSplashPage(self,buddy):
      filename = buddy.group;

      img = gtk.Image();
      img.set_from_file(filename);
      img.show();
      
      n = self.notebook.get_n_pages();
      conv = conversation.Conversation(buddy);
      self.notebook.append_page(img,None);
      pres = constants.Presence(None,"",filename);
      self.drawLabel("Splash",pres,n,buddy.jid);
      self.convs.addConversation(conv);

      return n;

   def drawPrivatePage(self,buddy):
      n = self.notebook.get_n_pages();

      conv = conversation.Conversation(buddy);
      
      conv.view = htmltextview.HtmlTextView()
      conv.view.connect('url-clicked',self.sigs.on_url_clicked);
      conv.view.set_pixels_above_lines(4);
      conv.view.set_left_margin(6);
      conv.view.set_right_margin(6);
      conv.view.set_wrap_mode(gtk.WRAP_WORD);
      buf = conv.view.get_buffer();
      buf.create_mark("end",buf.get_end_iter(),False);
      conv.view.show();

      scrollWindow = gtk.ScrolledWindow();
      scrollWindow.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC);
      scrollWindow.add(conv.view);
      scrollWindow.show();
      
      vbox = gtk.VBox();
      vbox.pack_start(scrollWindow,True,True,4);
      vbox.pack_end(self.controls(conv),False,False,4);
      vbox.show();

      self.notebook.append_page(vbox,None);      
      self.drawLabel(str(buddy.name),constants.C.presences[buddy.presence],
                     n,buddy.jid);
      self.convs.addConversation(conv);
      
      return n;
      
   def drawChatPage(self,room):
      n = self.notebook.get_n_pages();
      conv = conversation.Conversation(room);
      conv.private = False;
      conv.mxtab = multimxTab.multiMxTab(self.blend,conv);

      self.notebook.append_page(conv.mxtab.vbox,None);      
      self.drawLabel(str(room.name),constants.C.types[handles.BuddyType.ROOM],
                     n,room.jid);
      self.convs.addConversation(conv);

      return n;
   
   def drawGalleryPage(self):
      pass;
    
      
   ### MENU ###
   def drawConversationMenuList(self,accel_group):
      separator = gtk.SeparatorMenuItem();
      separator.show();
      
      separator2 = gtk.SeparatorMenuItem();
      separator2.show();

      self.findMenuItem = gtk.ImageMenuItem(_("_Find"));
      findImage = gtk.Image();
      findImage.set_from_stock(gtk.STOCK_FIND,gtk.ICON_SIZE_MENU);
      self.findMenuItem.set_image(findImage);
      self.findMenuItem.connect("activate",self.sigs.on_find);
      self.findMenuItem.add_accelerator("activate", accel_group,ord('F'),
                                        gtk.gdk.CONTROL_MASK,gtk.ACCEL_VISIBLE);
      self.findMenuItem.show();

      self.viewLogMenuItem = gtk.MenuItem(_("_View Log"));
      self.viewLogMenuItem.connect("activate",self.sigs.on_view_log);
      self.viewLogMenuItem.show();
      
      self.sendFileMenuItem = gtk.ImageMenuItem(_("_Send File"));
      sendFileImage = gtk.Image();
      sendFileImage.set_from_stock(gtk.STOCK_FILE,gtk.ICON_SIZE_MENU);
      self.sendFileMenuItem.set_image(sendFileImage);
      self.sendFileMenuItem.connect("activate",self.sigs.on_send_file);
      self.sendFileMenuItem.show();

      self.saveChatGalleryMenuItem = gtk.ImageMenuItem(_("_Save Chat to Gallery"));
      saveChatGalleryImage = gtk.Image();
      saveChatGalleryImage.set_from_stock(gtk.STOCK_SAVE,gtk.ICON_SIZE_MENU);
      self.saveChatGalleryMenuItem.set_image(saveChatGalleryImage);
      self.saveChatGalleryMenuItem.connect("activate",self.sigs.on_save_gallery);
      self.saveChatGalleryMenuItem.show();

      closeConvMenuItem = gtk.ImageMenuItem(_("_Close Conversation"));
      closeConvImage = gtk.Image();
      closeConvImage.set_from_stock(gtk.STOCK_CLOSE,gtk.ICON_SIZE_MENU);
      closeConvMenuItem.set_image(closeConvImage);
      closeConvMenuItem.connect("activate",self.sigs.on_close_conv);
      closeConvMenuItem.show();
      
      convSubmenu = gtk.Menu();
      convSubmenu.append(self.findMenuItem);
      convSubmenu.append(self.viewLogMenuItem);
      convSubmenu.append(separator);
      convSubmenu.append(self.sendFileMenuItem);
      convSubmenu.append(self.saveChatGalleryMenuItem);
      convSubmenu.append(separator2);
      convSubmenu.append(closeConvMenuItem);
      convSubmenu.show();
      convList = gtk.MenuItem(_("_Conversation"));
      convList.set_submenu(convSubmenu);
      convList.show();
      
      return convList;


   def drawOptionsMenuList(self,accel):
      self.loggingMenuItem = gtk.CheckMenuItem(_("_On Record"));
      self.loggingMenuItem.connect("activate",self.sigs.on_logging);
      self.loggingMenuItem.set_active(True);
      self.loggingMenuItem.show();

      self.encryptMenuItem = gtk.CheckMenuItem(_("_Encrypt Messages"));
      self.encryptMenuItem.connect("activate",self.sigs.on_encrypt);
      self.encryptMenuItem.show();      


      optSubmenu = gtk.Menu();
      optSubmenu.append(self.loggingMenuItem);
      optSubmenu.append(self.encryptMenuItem);
      optSubmenu.show();
      optList = gtk.MenuItem(_("_Options"));
      optList.set_submenu(optSubmenu);
      optList.show();
      
      return optList;

   def drawMenu(self,accel):
      menu = gtk.MenuBar();
      menu.append(self.drawConversationMenuList(accel));
      menu.append(self.drawOptionsMenuList(accel));
      menu.show();
      
      return menu;

   ### FORMAT METHODS ###

   def addTagsToBuffer(self,conv):
      buf = conv.convEntry.get_buffer();

      bold = buf.create_tag("bold");
      bold.set_property('weight',pango.WEIGHT_BOLD);

      italics = buf.create_tag("italics");
      italics.set_property('style',pango.STYLE_ITALIC);

      underline = buf.create_tag("underline");
      underline.set_property('underline',pango.UNDERLINE_SINGLE);

      big = buf.create_tag("big");
      big.set_property('scale',pango.SCALE_LARGE);
      
      small = buf.create_tag("small");
      small.set_property('scale',pango.SCALE_SMALL);

      highlight = buf.create_tag("highlight");
      highlight.set_property('foreground-gdk',gtk.gdk.color_parse("#7FA5E3"));


   # This keeps formatting the text if a format option has been
   # toggled.
   def _keepformat(self):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      if conv.format_strong == True:    # BOLD
         buf = conv.convEntry.get_buffer();
         iter = buf.get_end_iter();
         iterS = iter.copy();
         iterS.backward_char();
         buf.apply_tag(buf.tag_table.lookup('bold'),iterS,iter);
      elif conv.format_italic == True:   # ITALIC
         buf = conv.convEntry.get_buffer();
         iter = buf.get_end_iter();
         iterS = iter.copy();
         iterS.backward_char();
         buf.apply_tag(buf.tag_table.lookup('italics'),iterS,iter);
      elif conv.format_undrli == True:   # UNDERLINE
         buf = conv.convEntry.get_buffer();
         iter = buf.get_end_iter();
         iterS = iter.copy();
         iterS.backward_char();
         buf.apply_tag(buf.tag_table.lookup('underline'),iterS,iter);
      elif conv.format_big != False:    # BIG
         buf = conv.convEntry.get_buffer();
         iter = buf.get_end_iter();
         iter.backward_char()
         if iter.get_char() == " ":
            iter.forward_char()
            self._doneformat(None,4)
            return;
         else:
            iter = buf.get_end_iter();
            iterS = iter.copy();
            iterS.backward_char();
            buf.apply_tag(buf.tag_table.lookup('big'),iterS,iter);
      elif conv.format_small != False:   # SMALL
         buf = conv.convEntry.get_buffer();
         iter = buf.get_end_iter();
         iter.backward_char()
         if iter.get_char() == " ":
            iter.forward_char()
            self._doneformat(None,5)
            return
         else:
            iter = buf.get_end_iter();
            iterS = iter.copy();
            iterS.backward_char();
            buf.apply_tag(buf.tag_table.lookup('small'),iterS,iter);
      elif conv.format_hilite != False: # HIGHLIGHT
         buf = conv.convEntry.get_buffer();
         iter = buf.get_end_iter();
         iterS = iter.copy();
         iterS.backward_char();
         buf.apply_tag(buf.tag_table.lookup('highlight'),iterS,iter);
      elif conv.format_colour != False: # COLOUR
         buf = conv.convEntry.get_buffer();
         iter = buf.get_end_iter();
         try:
            colTag = buf.create_tag(str('textcol:'+conv.format_colour.to_string()));
            colTag.set_property('foreground-gdk',conv.format_colour);
         except TypeError: # It's already in the table
            colTag = buf.tag_table.lookup(str('textcol:'+conv.format_colour.to_string()));
         iterS = iter.copy();
         iterS.backward_char();
         buf.apply_tag(colTag,iterS,iter);
     
      return False;

   def _doneallformat(self,buttons):
      widgets = buttons.get_children();
      for i in range(1,len(widgets)):
         widgets[i].set_active(False);
         #self._doneformat(widgets[i],(i-1));
      
   def _doneformat(self,widget,i):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      if conv.getFormat(i) != False:
         #iter = buf.get_iter_at_mark(buf.get_mark('insert'));
         #invisibleTag = buf.create_tag();
         #invisibleTag.set_property('invisible',True);

         if i == 0:   # BOLD
            #buf.insert_with_tags(iter,'*',invisibleTag);
            conv.format_strong = False;
         elif i == 1:   # ITALIC
            #buf.insert_with_tags(iter,'/',invisibleTag);
            conv.format_italic = False;
         elif i == 2:   # UNDERLINE
            #buf.insert_with_tags(iter,'_',invisibleTag);
            conv.format_undrli = False;
         elif i == 3:   # HIGHLIGHT
            #buf.insert_with_tags(iter,'$',invisibleTag);
            conv.format_hilite = False;
         elif i == 4:   # BIG TEXT
            conv.format_big = False;
         elif i == 5:   # SMALL TEXT
            conv.format_small = False;
         elif i == 6:   # COLOUR
            #buf.insert_with_tags(iter,'#??????',invisibleTag);
            conv.format_colour = False;


   def _underline(self,widget):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      #invisibleTag = buf.create_tag();
      #invisibleTag.set_property('invisible',True);
      
      # See if the text is selected, if not assume the
      # startIter is where the cursor is
      if buf.get_has_selection():
         (startIter,endIter) = buf.get_selection_bounds();
         widget.set_active(False);
         buf.apply_tag(buf.tag_table.lookup('underline'),startIter,endIter);        
         #buf.insert_with_tags(endIter,'_',invisibleTag);
         #(startIter,endIter) = buf.get_selection_bounds();
         #buf.insert_with_tags(startIter,'_',invisibleTag);

         conv.format_undrli = False;
         return;
      else:
         endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
         startIter = endIter.copy();
         startIter.backward_char();

         conv.format_undrli = True;

         buf.apply_tag(buf.tag_table.lookup('underline'),startIter,endIter);
         #buf.insert_with_tags(startIter,'_',invisibleTag);
         return;



   def _italic(self,widget):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      #invisibleTag = buf.create_tag();
      #invisibleTag.set_property('invisible',True);
      
      # See if the text is selected, if not assume the
      # startIter is where the cursor is
      if buf.get_has_selection():
         (startIter,endIter) = buf.get_selection_bounds();
         widget.set_active(False);
         buf.apply_tag(buf.tag_table.lookup('italics'),startIter,endIter);        
         #buf.insert_with_tags(endIter,'/',invisibleTag);
         #(startIter,endIter) = buf.get_selection_bounds();
         #buf.insert_with_tags(startIter,'/',invisibleTag);

         conv.format_italic = False;
      else:
         endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
         startIter = endIter.copy();
         startIter.backward_char();

         conv.format_italic = True;

         buf.apply_tag(buf.tag_table.lookup('italics'),startIter,endIter);
         #buf.insert_with_tags(startIter,'/',invisibleTag);
         return;



   def _bold(self,widget):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      #invisibleTag = buf.create_tag();
      #invisibleTag.set_property('invisible',True);
      
      # See if the text is selected, if not assume the
      # startIter is where the cursor is and the endIter
      # is the end of the buffer.
      
      if buf.get_has_selection():
         (startIter,endIter) = buf.get_selection_bounds();
         widget.set_active(False);
         buf.apply_tag(buf.tag_table.lookup('bold'),startIter,endIter);        
         #buf.insert_with_tags(endIter,'*',invisibleTag);
         #(startIter,endIter) = buf.get_selection_bounds();
         #buf.insert_with_tags(startIter,'*',invisibleTag);

         conv.format_strong = False;
         return;
      else:
         endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
         startIter = endIter.copy();
         startIter.backward_char();

         conv.format_strong = True;

         buf.apply_tag(buf.tag_table.lookup('bold'),startIter,endIter);
         #buf.insert_with_tags(startIter,'*',invisibleTag);
         return;



   def _colour(self,col,widget):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();
      
      #invisibleTag = buf.create_tag();
      #invisibleTag.set_property('invisible',True);

      txtColour = self.__color_to_hex(col);            
      
      # See if the text is selected, if not assume the
      # startIter is where the cursor is and the endIter
      # is the end of the buffer.
      
      if buf.get_has_selection():
         (startIter,endIter) = buf.get_selection_bounds();
         widget.set_active(False);
         try:
            colrTag = buf.create_tag(name=str('textcol:'+col.to_string()));
            colrTag.set_property('foreground-gdk',col);
         except TypeError:
            colrTag = buf.tag_table.lookup(str('textcol:'+col.to_string()));
         buf.apply_tag(colrTag,startIter,endIter);        
         #buf.insert_with_tags(endIter,'#??????',invisibleTag);
         #(startIter,endIter) = buf.get_selection_bounds();
         #buf.insert_with_tags(startIter,txtColour,invisibleTag);

         conv.format_colour = False;
      else:
         endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
         startIter = endIter.copy();
         startIter.backward_char();

         conv.format_colour = col;
         try:
            colrTag = buf.create_tag(str('textcol:'+col.to_string()));
            colrTag.set_property('foreground-gdk',col);
         except TypeError:
            colrTag = buf.tag_table.lookup(str('textcol:'+col.to_string()));
         buf.apply_tag(colrTag,startIter,endIter);
         #buf.insert_with_tags(startIter,txtColour,invisibleTag);
         return;

   def _bigText(self,widget):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      #invisibleTag = buf.create_tag();
      #invisibleTag.set_property('invisible',True);
      
      # See if the text is selected, if not assume the
      # startIter is where the cursor is and the endIter
      # is the end of the buffer.
      
      if buf.get_has_selection():
         (startIter,endIter) = buf.get_selection_bounds();
         widget.set_active(False);
         buf.apply_tag(buf.tag_table.lookup('big'),startIter,endIter);        
         #buf.insert_with_tags(endIter,'.+',invisibleTag);
         conv.format_big = False;
         return;
      else:
         endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
         startIter = endIter.copy();
         startIter.backward_char();

         conv.format_big = True;

         buf.apply_tag(buf.tag_table.lookup('big'),startIter,endIter);
         #buf.insert_with_tags(startIter,'.+',invisibleTag);
         return;

   def _smallText(self,widget):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      #invisibleTag = buf.create_tag();
      #invisibleTag.set_property('invisible',True);
      
      # See if the text is selected, if not assume the
      # startIter is where the cursor is and the endIter
      # is the end of the buffer.
      
      if buf.get_has_selection():
         (startIter,endIter) = buf.get_selection_bounds();
         widget.set_active(False);
         buf.apply_tag(buf.tag_table.lookup('small'),startIter,endIter);        
         #buf.insert_with_tags(endIter,'.-',invisibleTag);
         conv.format_small = False;
         return;
      else:
         endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
         startIter = endIter.copy();
         startIter.backward_char();

         conv.format_small = True;

         buf.apply_tag(buf.tag_table.lookup('small'),startIter,endIter);
         #buf.insert_with_tags(startIter,'.-',invisibleTag);
         return;


   def _highlight(self,widget):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();

      #invisibleTag = buf.create_tag();
      #invisibleTag.set_property('invisible',True);
      
      # See if the text is selected, if not assume the
      # startIter is where the cursor is and the endIter
      # is the end of the buffer.
      
      if buf.get_has_selection():
         (startIter,endIter) = buf.get_selection_bounds();
         widget.set_active(False);
         #buf.insert_with_tags(endIter,'$',invisibleTag);
         #(startIter,endIter) = buf.get_selection_bounds();
         #buf.insert_with_tags(startIter,'$',invisibleTag);

         buf.apply_tag(buf.tag_table.lookup('highlight'),startIter,endIter);

         conv.format_hilite = False;
         return;
      else:
         endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
         startIter = endIter.copy();
         startIter.backward_char();

         conv.format_hilite = True;

         buf.apply_tag(buf.tag_table.lookup('highlight'),startIter,endIter);

         #buf.insert_with_tags(startIter,'$',invisibleTag);
         return;


   # For now this will just have to display the pattern and not the emoticon
   # until I can figure out a better way to this.. probably won't have time
   # before the competition ends, though.
   def _insertEmote(self,txt,img):
      n = self.notebook.get_current_page();
      conv = self.convs.getByPageNumber(n);
      buf = conv.convEntry.get_buffer();
      startIter = buf.get_iter_at_mark(buf.get_mark('insert'));
      #buf.insert(startIter,txt);

      """
      invisibleTag = buf.create_tag();
      invisibleTag.set_property('invisible',True);

      startIter = buf.get_iter_at_mark(buf.get_mark('insert'));
      buf.insert_with_tags(startIter,txt,invisibleTag);
      startIter = buf.get_iter_at_mark(buf.get_mark('insert'));
      """

      try:
         tag = imageTextTag(name=str("emote:" + txt));
         tag.emotePattern = txt;
         buf.tag_table.add(tag);
      except ValueError:
         tag = buf.tag_table.lookup(str("emote:" + txt))

      startIter = buf.get_iter_at_mark(buf.get_mark('insert'));

      if type(img) == type(""):
         pBuf = gtk.gdk.pixbuf_new_from_file(img);
      else:
         pBuf = img;
      buf.insert_pixbuf(startIter,pBuf);

      # Apply tag
      endIter = buf.get_iter_at_mark(buf.get_mark('insert'));
      startIter = endIter.copy();
      startIter.backward_char();
      
      buf.apply_tag(tag,startIter,endIter);



   # Attribution: https://forja.rediris.es/plugins/scmsvn/viewcvs.php/*checkout*/src/Editor/editor.py?root=csl2-sdocente&rev=32
   def __color_to_hex(self,colour):
      hexstring = ""
      for col in 'red','green','blue':
         hexfrag = hex(getattr(colour,col) / (16 * 16)).split("x")[1]
         if len(hexfrag) < 2:
            hexfrag = "0" + hexfrag
         
         hexstring += hexfrag
      return "#" + hexstring

   def __debugTags(self,tags):
      ret = [];
      for i in range(0,len(tags)):
         ret.append(tags[i].get_property('name'));
      return ret;

   def __weird_sort(self,order,closing):
      sorted = [];
      for i in range(0,len(order)):
         index = order[i];
         sorted.append(closing[index]);
      sorted.reverse();
      return sorted;


   # Just don't ask... There are a couple of redundant things
   # but .. yeah.. it works so get over it.
   def createMarkedupMessage(self,conv):
      buf = conv.convEntry.get_buffer();
      
      output='';
      later = '';
      
      found=False;
      order=[]; #appended must be: 0 - Bold, 1 - Italics, 2 - Underline, 3 - Highlight, 4 - Colour
      closing = [False,False,False,False,False]; # index 0 = bold, 1 = italics, etc.
      markup = [False,False,False,False,False]; # index 0 = bold, i = italics, etc.

      iter = buf.get_start_iter();
      fail = False;
      keep = True;
      while fail == False:
         tags = iter.get_tags();
         # EMOTICON
         if iter.get_char() == 0xFFFC or iter.get_char() == "\xef\xbf\xbc":
            tags = iter.get_tags();
            for i in range(0,len(tags)):
               if hasattr(tags[i],'emotePattern'):
                  output += tags[i].emotePattern;
                  break;
         # ANOTHER TEXT TAG MAYBE?
         elif iter.get_char() != "\0":
            if len(tags) == 0:
               output += iter.get_char();
            else:            
               # BOLD
               if iter.begins_tag(buf.tag_table.lookup('bold')):
                  output += '*';
                  tags.remove(buf.tag_table.lookup('bold'));
                  markup[0] = True;
                  order.append(0);
               else:
                  if markup[0] == True:
                     iS = iter.copy();
                     iS.forward_char();
                     try:
                        iS.get_tags().index(buf.tag_table.lookup('bold'));
                     except ValueError:
                        # No bold next. Kill
                        closing[0] = '*';

               # ITALICS
               if iter.begins_tag(buf.tag_table.lookup('italics')):
                  output += '/';
                  tags.remove(buf.tag_table.lookup('italics'));
                  markup[1] = True;
                  order.append(1);
               else:
                  if markup[1] == True:
                     iS = iter.copy();
                     iS.forward_char();
                     try:
                        iS.get_tags().index(buf.tag_table.lookup('italics'));
                     except ValueError:
                        # No italics next. Kill
                        closing[1] = '/';

               # UNDERLINE
               if iter.begins_tag(buf.tag_table.lookup('underline')):
                  output += '_';
                  tags.remove(buf.tag_table.lookup('underline'));
                  markup[2] = True;
                  order.append(2);
               else:
                  if markup[2] == True:
                     iS = iter.copy();
                     iS.forward_char();
                     try:
                        iS.get_tags().index(buf.tag_table.lookup('underline'));
                     except ValueError:
                        # No underline next. Kill
                        closing[2] = '_';

               # HIGHLIGHT
               if iter.begins_tag(buf.tag_table.lookup('highlight')):
                  output += '$';
                  tags.remove(buf.tag_table.lookup('highlight'));
                  markup[3] = True;
                  order.append(3);
               else:
                  if markup[3] == True:
                     iS = iter.copy();
                     iS.forward_char();
                     try:
                        iS.get_tags().index(buf.tag_table.lookup('highlight'));
                     except ValueError:
                        # No highlight next. Kill
                        closing[3] = '$'; 
   
               # BIGGER TEXT
               if iter.begins_tag(buf.tag_table.lookup('big')):
                  output += '.+';
                  tags.remove(buf.tag_table.lookup('big'));
   
               # SMALLER TEXT
               if iter.begins_tag(buf.tag_table.lookup('small')):
                  output += '.-';
                  tags.remove(buf.tag_table.lookup('small'));
   
               # COLOUR
               for i in range(0,len(tags)):
                  if tags[i].get_property('foreground-set') == True:
                     found=True;
                     if markup[4] == False:
                        if tags[i].get_property('name').startswith('textcol'):
                           col = tags[i].get_property('foreground-gdk');
                           colour = self.__color_to_hex(col);
                           output += colour;
                           markup[4] = True;
                           order.append(4);
                           break;
                  else:
                     found=True;
               
               if found == False and markup[4] == True:
                  closing[4] = '#??????';
   
               sorted = self.__weird_sort(order,closing);
               for i in range(0,len(sorted)):
                  if sorted[i] != False:
                     later += sorted[i];
               for i in range(0,len(closing)):
                  if closing[i] != False:
                     closing[i] = False;
                     markup[i] = False;
                     order.remove(i);
                     
               output += iter.get_char() + later;
               later = '';
         if keep == False:
            fail = True;
         else:
            keep = iter.forward_char();
      return output;


class imageTextTag(gtk.TextTag):
   emotePattern = '';

   def __init__(self,name=None):
      gtk.TextTag.__init__(self,name);